package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    OrderMapper orderMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    OrderDetailMapper orderDetailMapper;
    @Autowired
    WorkspaceService workspaceService;

    /**
     * 营业额统计
     *
     * @param begin
     * @param end
     * @return
     */
    public TurnoverReportVO turnOver(LocalDate begin, LocalDate end) {
//       1. 进行时间的处理
//        首先创建一个封装时间的集合
        List<LocalDate> timeList =timeHandle(begin,end);
//       把集合的元素对象转为字符串
        String timeString = StringUtils.join(timeList, ",");

//       2. 进行数量的统计
//        创建集合收集每一个时间点的营业额
        List<Double> statisticsList = new ArrayList<>();
//        因为数据库的时间是LocalDateTime，有时分秒的，所以通过LocalDate构造出LocalDateTime
//        遍历时间
        for (LocalDate localDate : timeList) {
            LocalDateTime beginDateTIme = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endDateTIme = LocalDateTime.of(localDate, LocalTime.MAX);
//            订单的状态为完成的订单 status = 5
            Integer completed = Orders.COMPLETED;
//            封装上面三个的数据
            Map map = new HashMap();
            map.put("begin", beginDateTIme);
            map.put("end", endDateTIme);
            map.put("status", completed);
//          进行数据库的查表
            Double statistics = orderMapper.selectStatistics(map);
//            避免数据库没有该时间的数据而返回空，空就就是0.0
            if (statistics == null){
                statistics = 0.0;
            }
//            数据对丢进集合里面
            statisticsList.add(statistics);
        }
//        将数据集合里面的数据字符串化
        String dataString = StringUtils.join(statisticsList, ",");
//        封装返回的对象
        TurnoverReportVO build = TurnoverReportVO.builder()
                .dateList(timeString)
                .turnoverList(dataString)
                .build();
        return build;
    }

    /**
     * 用户数量统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        //       1. 进行时间的处理
//        首先创建一个封装时间的集合
        List<LocalDate> timeList =timeHandle(begin,end);
//       把集合的元素对象转为字符串
        String timeString = StringUtils.join(timeList, ",");

//        2.进行用户数量的统计
//        总的用户
        List<Integer> totalUser = new ArrayList<>();
//        新增的用户数量
        List<Integer> newUser = new ArrayList<>();
//        对时间点的用户进行统计，然后加入对应的数据集合里
        for (LocalDate localDate : timeList) {
//           因为数据库的时间是LocalDateTime，有时分秒的，所以通过LocalDate构造出LocalDateTime
            LocalDateTime beginDateTIme = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endDateTIme = LocalDateTime.of(localDate, LocalTime.MAX);

//            借用集合封装
            Map map = new HashMap();
//            查询总的
            map.put("end",endDateTIme);
            Integer total = userMapper.countId(map);
//              避免为空
            if (total == null){
                total = 0;
            }
            totalUser.add(total);
//            查询新增的
            map.put("begin",beginDateTIme);
            Integer news = userMapper.countId(map);
//            避免为空
            if (news == null){
                news = 0;
            }
            newUser.add(news);
        }

//        将集合进行字符串化
        String totalUserStr = StringUtils.join(totalUser, ",");
        String newUserStr = StringUtils.join(newUser, ",");
//        封装返回的对象
       return UserReportVO.builder()
                .dateList(timeString)
                .totalUserList(totalUserStr)
                .newUserList(newUserStr)
                .build();
    }

    /**
     * 订单的统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO orderStatistics(LocalDate begin, LocalDate end) {

        //       1. 进行时间的处理
//        首先创建一个封装时间的集合
        List<LocalDate> timeList =timeHandle(begin,end);
//       把集合的元素对象转为字符串
        String timeString = StringUtils.join(timeList, ",");

//        2.计算每日的订单数，分为有效订单与总的订单数
        List<Integer> totalOrderList = new ArrayList<>();
        List<Integer> validOrderList = new ArrayList<>();
//        总的订单数与总的有效订单
        Integer totalOrders = 0;
        Integer validOrders = 0;
//        对每天的进行总结
//        循环遍历时间timeList
        for (LocalDate localDate : timeList) {
            //           因为数据库的时间是LocalDateTime，有时分秒的，所以通过LocalDate构造出LocalDateTime
            LocalDateTime dayBeginDateTIme = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime dayEndDateTIme = LocalDateTime.of(localDate, LocalTime.MAX);
            //            借用集合封装
            Map map = new HashMap();
//            查询总的
            map.put("begin",dayBeginDateTIme);
            map.put("end",dayEndDateTIme);
            Integer total = orderMapper.countId(map);
//            避免为空
            if (total == null){
                total = 0;
            }
//            把一天的订单加到总的去
            totalOrders += total; // 也可以使用流计算totalOrderList.stream().reduce(Integer::sum);
            totalOrderList.add(total);

//            查询有效的
            map.put("status",Orders.COMPLETED);
            Integer  valid= orderMapper.countId(map);
            if (valid == null){
                valid = 0;
            }
//            把一天有效的加到总有效去
            validOrders += valid;// 也可以使用流计算validOrderList.stream().reduce(Integer::sum);
            validOrderList.add(valid);
        }
//        计算订单的完成率 有效的/总的
        Double orderCompletionRate = 0.0;
        if (totalOrders != 0){
            orderCompletionRate = validOrders.doubleValue()/totalOrders;// (double) (validOrders/totalOrders);不行
        }

//        构建返回的封装对象
        return  OrderReportVO.builder()
                .dateList(timeString) // 时间x轴
                .orderCountList(StringUtils.join(totalOrderList,","))// 每天总的订单数y轴
                .validOrderCountList(StringUtils.join(validOrderList,","))// 每天有效的订单数y轴
                .totalOrderCount(totalOrders)// 总的订单数
                .validOrderCount(validOrders)// 有效的订单数
                .orderCompletionRate(orderCompletionRate)// 完成率
                .build();
    }

    /**
     * 销量前十的统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO topStatistics(LocalDate begin, LocalDate end) {
//        查询的时间范围
        LocalDateTime beginDateTIme = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endDateTIme = LocalDateTime.of(end, LocalTime.MAX);

//        销量前十的名字
        List<String> nameList = new ArrayList<>();
//        销量前是的数量
        List<Integer> numberList = new ArrayList<>();
//        查数据库
        List<GoodsSalesDTO> goodsSalesDTO = orderDetailMapper.selectNameAndSumNumber(beginDateTIme, endDateTIme);
//        一个一个对象取
        for (GoodsSalesDTO salesDTO : goodsSalesDTO) {

//            名字插入 // 也可以使用stream流List<String> nameList = goodsSalesDTO.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
            nameList.add(salesDTO.getName());
//            数量插入List<Integer> numberList = goodsSalesDTO.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
            numberList.add(salesDTO.getNumber());

        }
//        将集合字符串化，然后封装返回数据
        return SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(nameList,","))
                .numberList(StringUtils.join(numberList,","))
                .build();
    }

    private List<LocalDate> timeHandle(LocalDate begin, LocalDate end){
        //       1. 进行时间的处理
//        首先创建一个封装时间的集合
        List<LocalDate> timeList = new ArrayList<>();
//        先插入第一个就是begin
        timeList.add(begin);
//         循环插入
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
//           加进去
            timeList.add(begin);
        }
        return timeList;
    }

    /**
     * 数据导出模块
     * @param response
     */
    @Override
    public void exportBusinessData(HttpServletResponse response) {
//        1.填充概览的数据
//        1-1先进行时间的处理
        LocalDate now = LocalDate.now();
//        开始的时间
        LocalDate beginDate = now.minusDays(30);
//        结束的时间
        LocalDate endDate = now.minusDays(1);
//        date为dateTime
        LocalDateTime beginM = LocalDateTime.of(beginDate,LocalTime.MIN);
        LocalDateTime endM = LocalDateTime.of(endDate,LocalTime.MAX);
//        1-2进行数据的查询
//        调用工作台的服务类，查出对应时间段的对象
        BusinessDataVO businessData = workspaceService.getBusinessData(beginM, endM);
//        获取模板的路径
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        try {
//            创建出对应模板的文件
            XSSFWorkbook sheets = new XSSFWorkbook(resourceAsStream);
//            获取到对应的表
            XSSFSheet sheet = sheets.getSheet("Sheet1");
//            表的第二行第二个格子放时间
            sheet.getRow(1).getCell(1).setCellValue("时间："+beginDate + "->" +endDate);
//            第四行第三个格子营业额
            sheet.getRow(3).getCell(2).setCellValue(businessData.getTurnover());
//            第四行第五个格子订单完成率
            sheet.getRow(3).getCell(4).setCellValue(businessData.getOrderCompletionRate());
//            第四行第七个格子新增用户数
            sheet.getRow(3).getCell(6).setCellValue(businessData.getNewUsers());
//            第五行第三个格子有效订单数
            sheet.getRow(4).getCell(2).setCellValue(businessData.getValidOrderCount());
//            第五行第五个格子平均客价
            sheet.getRow(4).getCell(4).setCellValue(businessData.getUnitPrice());

//            2.填充详情的数据
//            2-1遍历30天，计算每一天的
            for (int i = 0; i < 30; i++) {
                LocalDate date = beginDate.plusDays(i);
//                一天时间对应的
                BusinessDataVO dataD =
                        workspaceService.getBusinessData(LocalDateTime.of(date,LocalTime.MIN), LocalDateTime.of(date,LocalTime.MAX));
//                2-2填充数据
//                都是那一行，逐增
                XSSFRow row = sheet.getRow(7 + i);
//                第八行第二个格子日期
                row.getCell(1).setCellValue(date.toString());
//                第八行第三个格子营业额
                row.getCell(2).setCellValue(dataD.getTurnover());
//                第八行第四个格子有效订单
                row.getCell(3).setCellValue(dataD.getValidOrderCount());
//                第八行第五个格子日订单完成率
                row.getCell(4).setCellValue(dataD.getOrderCompletionRate());
//                第八行第六个格子平均客单价
                row.getCell(5).setCellValue(dataD.getUnitPrice());
//                第八行第七个格子新增用户
                row.getCell(6).setCellValue(dataD.getNewUsers());
            }

//            3.输出报表
//            3-1 通过输出流将Excel文件下载到客户端浏览器
            ServletOutputStream out = response.getOutputStream();
            sheets.write(out);

//            3-2关闭资源
            out.close();
            sheets.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
